<template>
  <div style="width: 100%; height: 100%"></div>
</template>

<script>
import {
  Scene,
  PerspectiveCamera,
  WebGLRenderer,
  AxesHelper, // 坐标轴
  PlaneBufferGeometry, // 平面缓存几何模型
  MeshBasicMaterial, // 基础网孔材料：以简单着色方式绘制几何形状的材料
  MeshLambertMaterial, // 兰伯特网孔材料： 非发光材料
  Mesh, // 网孔
  BoxGeometry, // 四边形的几何模型，通常用于创建具有“宽度”、“高度”和“深度”参数的立方体或不规则四边形模型
  SphereGeometry, // 用于创建球体几何模型的类
  SpotLight, // 聚光光源：投射锥形阴影区域的点光源
  AmbientLight
} from 'three'
import Stats from 'three/examples/js/libs/stats.min'
import Detector from 'three/examples/js/Detector'

export default {
  data() {
    return {
      scene: null,
      camera: null,
      renderer: null,
      ele: null,
      width: 0,
      height:0,
      stats: null,
      step: 0,
      cube: null,
      sphere: null
    }
  },
  mounted() {
    this.ele = this.$el
    this.width = this.$el.clientWidth
    this.height = this.$el.clientHeight

    if (!Detector.webgl) {
      const warning = Detector.getWebGLErrorMessage()
      this.ele.appendChild(warning)
    }
    this.threeStart()
  },
  methods: {
    initThree () {
      this.renderer = new WebGLRenderer()
      this.renderer.setSize(this.width, this.height)
      this.ele.appendChild(this.renderer.domElement)
      this.renderer.setClearColor(0xffffff, 1)
      this.renderer.shadowMap.enabled = true
    },
    initCamera () {
      this.camera = new PerspectiveCamera(45, this.width / this.height, 0.1, 1000)
      this.camera.position.x = -30
      this.camera.position.y = 40
      this.camera.position.z = 30
      this.camera.lookAt(0, 0, 0)
    },
    initScene () {
      this.scene = new Scene()
    },
    initAxis () {
      const axis = new AxesHelper(20)
      this.scene.add(axis)
    },
    initPlane () {
      const planeGeometry = new PlaneBufferGeometry(60, 30, 1, 1)
      // const planeMaterial = new MeshBasicMaterial({ color: '#aaaaaa' })
      const planeMaterial = new MeshLambertMaterial({ color: '#aaaaaa' })
      const plane = new Mesh(planeGeometry, planeMaterial)
      plane.rotation.x = -0.5 * Math.PI
      plane.position.x = 15
      plane.position.y = 0
      plane.position.z = 0
      plane.receiveShadow = true
      this.scene.add(plane)
    },
    addGeometry () {
      const cubeGeometry = new BoxGeometry(4, 4, 4)
      // const cubeMaterial = new MeshBasicMaterial({ color: 'yellow', wireframe: true })
      const cubeMaterial = new MeshLambertMaterial({ color: 'yellow', wireframe: false })
      this.cube = new Mesh(cubeGeometry, cubeMaterial)
      this.cube.position.x = -8
      this.cube.position.y = 4
      this.cube.position.z = 0
      this.cube.castShadow = true
      this.scene.add(this.cube)

      const sphereGeometry = new SphereGeometry(4, 20, 20)
      // const sphereMaterial = new MeshBasicMaterial({ color: 'red', wireframe: true })
      const sphereMaterial = new MeshBasicMaterial({ color: 'red', wireframe: false })
      this.sphere = new Mesh(sphereGeometry, sphereMaterial)
      this.sphere.position.x = 20
      this.sphere.position.y = 10
      this.sphere.position.z = 0
      this.sphere.castShadow = true
      this.scene.add(this.sphere)
    },
    addLight () {
      const spotLight = new SpotLight(0xffffff)
      spotLight.position.set(-40, 60, -10)
      spotLight.castShadow = true
      this.scene.add(spotLight)
    },
    initStats () { // 初始化监测动画运行频帧库stats
      const stats = new Stats()
      stats.setMode(0) // 0: 检测的是画面每秒传输帧数(fps); 1: 检测的是画面渲染的时间
      stats.domElement.style.position = 'relative'
      stats.domElement.style.left = '0px'
      stats.domElement.style.top = -1 * this.height + 'px'
      this.ele.appendChild(stats.domElement)
      return stats
    },
    renderScene () {
      requestAnimationFrame(this.renderScene)
      this.stats.update() // 通知stats：画面已经被重新渲染
      this.cube.rotation.x += 0.02
      this.cube.rotation.y += 0.02
      this.cube.rotation.z += 0.02
      this.step += 0.03
      this.sphere.position.x = 20 + (10 * Math.cos(this.step));
      this.sphere.position.y = 0 + (10 * Math.sin(this.step))
      this.renderer.clear()
      this.renderer.render(this.scene, this.camera)
    },
    threeStart () {
      this.initThree()
      this.initCamera()
      this.initScene()
      this.initAxis()
      this.initPlane()
      this.addGeometry()
      this.addLight()
      this.stats = this.initStats()
      this.renderScene()
      this.onWindowResize()
    },
    onWindowResize () {
      this.camera.aspect = this.width / this.height
      this.camera.updateProjectionMatrix()
      this.renderer.setSize( this.width, this.height )
    }
  }
}
</script>